#!/usr/bin/python3
# -*- coding:utf-8 -*-
""""
@Author: 李吉凯
@Email: lijk34925@hundsun.com
@Time: 2021/4/22 15:43
"""
import os.path
import json
from BladeFerm.Lib.ClassSelenium import *
from selenium.webdriver.common.keys import Keys
import time,datetime
from qturboframe.lib.webdriver.exceptions import SeleniumError
from selenium.webdriver.support.select import Select
from BladeFerm.utils.compareData import *
from BladeFerm.utils.WindowsOpration import uploadWin32
from BladeFerm.utils.dataoperation import UpdateCookies
from BladeFerm.utils.basic_opration import get_dir_file
import re
from time import sleep


# ------------ 以下都是浏览器操作 --------------------------------
def loginTS(username, password, url, isCloseBrower):
    '''
    功能：登录TS网页
    :param username: 用户名
    :param password: 密码
    :return: 返回 selenium 类初始化的对象 driver ；这个driver已经置为全局变量了，可以不接收返回值执行使用
    '''
    global driver
    if isCloseBrower == "是":
        isCloseBrower = True
    else:
        isCloseBrower = False
    driver = ClassSelenium('chrome', isCloseBrowser=isCloseBrower)
    driver.open_url(url)
    # 执行登陆操作
    element = driver.getElementByAttribute('xpath://input[@name="username"]')
    element.clear()
    element.send_keys(username)
    element = driver.getElementByAttribute('xpath://*[@id="password"]')
    element.clear()
    element.send_keys(password)
    element = driver.getElementByAttribute('xpath://*[@id="submit_psd"]/input').send_keys(Keys.ENTER)
    return driver

def login(username, password):
    '''
    功能：如果未登录，则输入密码和用户名进行登录并保存登录信息到本地cookies.json
    :param username: 用户名
    :param password: 密码
    :return: 返回 selenium 类初始化的对象 driver ；这个driver已经置为全局变量了，可以不接收返回值执行使用
    '''
    url = config.get('Browser', 'mainpage_url')
    browser_type = config.get('Browser', 'browser_type')
    close_brower = config.get('Browser', 'close_brower')
    downdir = os.path.join(ROOT_PATH, 'DownFiles')
    close_flag = True if close_brower == "True" else False
    global driver
    driver = ClassSelenium(browser_type, isCloseBrowser=close_flag, download=downdir)
    driver.open_url(url)
    # 执行登陆操作
    element = driver.getElementByAttribute('xpath://input[@name="username"]')
    element.clear()
    element.send_keys(username)
    element = driver.getElementByAttribute('id:user_password')
    element.clear()
    element.send_keys(password)
    # send_keys(Keys.ENTER) 替换 click() 后，可以兼容debug和非debug模式   // 李吉凯 20210526
    element = driver.getElementByAttribute('id:login_submit').send_keys(Keys.ENTER)
    time.sleep(0.5)
    cookies = driver.get_cookies()
    cookie_path = os.path.join(ROOT_PATH, 'login_cookies.yaml')
    resdata = UpdateCookies.saveCookies(cookie_path, username, cookies)
    return driver

def __judgeRunMode(setup_flag):
    PythonUnitFilter = config.get('TestFlow', 'PythonUnitFilter')
    if PythonUnitFilter == '1' and setup_flag is None:
        logger.info('########################Blade平台运行测试套模式，测试脚本调用########################')
        flag = True
    elif PythonUnitFilter == '1' and setup_flag is not None:
        logger.info('########################Blade平台运行测试套模式，__init__脚本调用########################')
        flag = False
    elif PythonUnitFilter == '0' and not setup_flag:
        logger.info('########################本地Unittest框架调试模式，测试脚本调用########################')
        flag = False
    elif PythonUnitFilter == '2' and not setup_flag:
        logger.info('########################本地Pytest框架调试模式，测试脚本调用########################')
        flag = True
    elif PythonUnitFilter == '2' and setup_flag:
        logger.info('########################本地Pytest框架调试模式，setup方法调用########################')
        flag = False
    else:
        logger.warning(f'###未知调试模式，请检查参数PythonUnitFilter：{PythonUnitFilter}，setup_flag：{setup_flag}的正确性###')
        flag = False
    return flag

def openWebPage(username=None, password="1", setup_flag=None):
    '''
    打开浏览器，已经登录直接打开主页，否则先登录再打开主页
    :param username: 用户名
    :param password: 密码
    :return: 返回True或False，表示是否是主页
    '''
    if __judgeRunMode(setup_flag):
        logger.info('Skip openWebPage(), driver opened already.')
        return False
    url = config.get('Browser', 'mainpage_url')
    browser_type = config.get('Browser', 'browser_type')
    close_brower = config.get('Browser', 'close_brower')
    downdir = os.path.join(ROOT_PATH, 'DownFiles')
    close_flag = True if close_brower == "True" else False
    global driver
    driver = ClassSelenium(browser_type, isCloseBrowser=close_flag, download=downdir)
    driver.open_url(url)
    cookie_path = os.path.join(ROOT_PATH, 'login_cookies.yaml')
    logger.info(f'Cookie file {cookie_path}')
    if os.path.exists(cookie_path) and username is None:
        cookies = UpdateCookies.getCookies(cookie_path)
        driver.add_cookies(cookies)
    elif os.path.exists(cookie_path) and username is not None:
        cookies = UpdateCookies.getCookies(cookie_path, username)
        if cookies:
            driver.add_cookies(cookies)
        else:
            login(username, password)
    else:
        login(username, password)
    driver.display_wait( 'xpath://div[@searchname="首页"]')
    result = check('首页', 'xpath://div[@searchname="首页"]', flag=1)
    return result

def switchAccount(username, password):
    '''
    切换账号操作
    :param username:
    :param password:
    :return:
    '''
    element = driver.getElementByAttribute('xpath://*[@id="header"]/div[2]/div/ul/li[8]/a')
    element.click()
    element = driver.getElementByAttribute('xpath://*[@id="frame_btn_exit"]')
    element.click()
    # 执行登陆操作
    element = driver.getElementByAttribute('xpath://input[@name="username"]')
    element.clear()
    element.send_keys(username)
    element = driver.getElementByAttribute('id:user_password')
    element.clear()
    element.send_keys(password)
    element = driver.getElementByAttribute('id:login_submit').send_keys(Keys.ENTER)
    time.sleep(0.5)
    cookies = driver.get_cookies()
    cookie_path = os.path.join(ROOT_PATH, 'login_cookies.yaml')
    resdata = UpdateCookies.saveCookies(cookie_path, username, cookies)
    foud_result = foundTargetElement(
        'xpath://span[@name="content_tablist_frame_navigation_athena_dijit_TemplatePanel_index"]', timeout=3)
    return foud_result

def openURL(target_url):
    '''
    功能：打开执行的URL页面
    :param target_url: url链接
    :return:
    '''
    driver.open_url(target_url)

def browerRefresh():
    driver.browerRefresh()
    res = driver.display_wait( 'xpath://div[@searchname="首页"]', timeout=10)
    assertResult(res)

def close(menuName='浏览器', setup_flag=None):
    '''
    功能：关闭测试的驱动
    :param menuName:
    :return:
    '''
    if __judgeRunMode(setup_flag):
        logger.info("Skip close(), driver cann't close.")
        return False
    # 关闭测试窗口
    driver.close()
    logger.info('关闭【%s】测试窗口 '% menuName)

def switchFrame(frameName, isParent=False):
    driver.switchToFrame(frameName, isParent)

# ------------ 以下都是点击操作 --------------------------------
def click(clickElement, msg='按钮', delay=0.1):
    '''
    功能：查找元素点击，只是为了log打印
    :param clickElement:
    :param msg:
    :param delay:
    :return:
    '''
    # 点击
    element = driver.getElementByAttribute(clickElement)
    element.click()
    sleep(delay)
    logger.info('点击"%s"' %msg)

def clickOfJS(clickElement, msg='JS执行', delay=0.1):
    '''
    功能：查找元素点击，只是为了log打印
    :param clickElement:
    :param msg:
    :param delay:
    :return:
    '''
    # 点击
    element = driver.getElementByAttribute(clickElement)
    driver.act_script(element.elementObj)
    sleep(delay)
    logger.info('点击"%s"' % msg)

def clickOfActionChains(clickElement, msg, delay=0.1):
    '''
    功能：查找元素点击，只是为了log打印
    :param clickElement:
    :param msg:
    :param delay:
    :return:
    '''
    # 点击
    element = driver.getElementByAttribute(clickElement)
    driver.leftClick(element.elementObj)
    sleep(delay)
    logger.info('点击"%s"' %msg)

def doubleclick(targetElement, msg=''):
    '''
    功能：查找元素，双击
    :param targetElement:
    :return:
    '''
    elementObj = driver.getElementByAttribute(targetElement)
    driver.doubleClick(elementObj)
    logger.info('双击"%s"' % msg)

def rightClick(targetElement):
    '''
    Function: 实现鼠标右击操作
    :param targetElement: 右击操作的元素
    :return:
    '''
    elementObj = driver.getElementByAttribute(targetElement)
    driver.rightClick(elementObj)
    logger.info('右键单击')

def add(addElement):
    '''
    功能：查找元素点击，只是为了log打印
    :param addElement:
    :return:
    '''
    # 点击添加
    element = driver.getElementByAttribute(addElement)
    element.click()
    logger.info('测试【添加】功能')
    logger.info('点击“添加”')

def update(updateDataElement, updateElement):
    '''
    功能：先选择要修改的元素，再点击修改按钮
    :param updateDataElement:
    :param updateElement:
    :return:
    '''
    # 点击修改
    element = driver.getElementByAttribute(updateDataElement)
    element.click()
    element = driver.getElementByAttribute(updateElement)
    element.click()
    logger.info('测试【修改】功能')
    logger.info('点击“修改”')

def delete(deleteDataElement, deleteElement):
    '''
    功能：先选择要删除的元素，再点击删除按钮
    :param deleteDataElement:
    :param deleteElement:
    :return:
    '''
    # 点击数据
    element = driver.getElementByAttribute(deleteDataElement)
    element.click()
    # 删除元素
    element = driver.getElementByAttribute(deleteElement)
    element.click()
    logger.info('测试【删除】功能')
    logger.info('点击“删除”')

def save(saveElement):
    '''
    功能：点击保存按钮
    :param saveElement:
    :return:
    '''
    element = driver.getElementByAttribute(saveElement)
    element.click()
    time.sleep(1.8)
    logger.info('点击“保存”')

def query(elementObj, exceptElement=None, time_delay=0):
    '''
    功能: 点击查询按钮
    :param elementObj:
    :return:
    '''
    # 点击查询
    element = driver.getElementByAttribute(elementObj)
    element.click()
    logger.info('点击“查询”')
    if exceptElement:
        driver.display_wait(exceptElement, timeout=10)
        logger.info('结果加载完成')
    time.sleep(time_delay)

def searchReport(elementObj, exceptElement=None):
    '''
    功能：用于点击查询按钮，进行报表查询操作。并等期望的元素或结果达标后再继续往下走，否则执行返回异常
    :param elementObj: 查询按钮对应的元素
    :param exceptElement: 期望出现的元素
    :return: 得到期望值返回True，如果超时都未找到则返回给平台可识别的指定异常
    '''
    element = driver.getElementByAttribute(elementObj)
    element.click()
    logger.info('测试【查询报表】功能')
    logger.info('点击“查询”')
    if exceptElement:
        result= driver.display_wait(exceptElement)
        if not result:
            raise SeleniumError(f'点击查询后未跳转到指定界面！查询元素是{exceptElement}')
    return True

def refresh(refreshElement):
    '''
    功能：点击刷新按钮
    :param refreshElement:
    :return:
    '''
    # 点击刷新
    element = driver.getElementByAttribute(refreshElement)
    element.click()
    logger.info('点击“刷新”')

def exportReport(elementObj, isContinue=True):
    '''
    功能：点击导出报告元素，如有弹框，默认点击确定
    :param elementObj:
    :param isContinue: 如有弹框，默认点击确定；若给的是False，则点击取消并返回异常
    :return:
    '''
    # 点击导出报表
    element = driver.getElementByAttribute(elementObj)
    element.click()
    logger.info('点击“导出”')
    # 如果弹出弹框，默认点击确认
    if isContinue:
        driver.getAlert()
        time.sleep(1)
        return True
    else:
        tx = driver.getAlert(alertFlag='dismiss')
        raise SeleniumError(f'弹框内容为{tx}，已经选择弹框取消！')

def export(elementObj, exportElementObj):
    '''
    功能：点击导出按钮（出现下载弹框），等待下载完成弹框关闭后继续
    :param elementObj:
    :param exportElementObj:
    :return:
    '''
    # 点击导出
    element = driver.getElementByAttribute(elementObj)
    element.click()
    logger.info('测试【导出】功能')
    logger.info('点击“导出”')
    element = driver.getElementByAttribute(exportElementObj)
    logger.info(element.getText())
    if not element:
        logger.info('下载框元素获取失败')
        raise SeleniumError(f'下载框元素获取失败!!!查找的元素是{exportElementObj}')
    elif element.getText() == str('正在下载请稍候') or element.getText() == str('正在导出请稍候'):
        # todo: 加入显示等待
        result = driver.display_wait(element, flag=5)
        logger.info('“导出”成功')
    # time.sleep(3)

def download(elementObj):
    '''
    功能：点击下载按钮元素
    :param elementObj:
    :return:
    '''
    element = driver.getElementByAttribute(elementObj)
    element.click()
    time.sleep(1)
    logger.info('点击“下载”')

def calculate(selectElement, calculateElement):
    '''
    功能：点击计算按钮，净资本操作
    :param selectElement:
    :param calculateElement:
    :return:
    '''
    # 计算
    element = driver.getElementByAttribute(selectElement)
    element.click()
    element = driver.getElementByAttribute(calculateElement)
    element.click()
    time.sleep(2)
    logger.info('点击“计算”')

def snapshot(snapshotElement, checkSnapshotElement):
    '''
    功能：点击快照按钮，确认是否保存成功
    :param snapshotElement:
    :param checkSnapshotElement:
    :return:
    '''
    # 测试快照
    element = driver.getElementByAttribute(snapshotElement)
    element.click()
    logger.info('测试【快照】功能')
    logger.info('点击“快照”')
    time.sleep(3)
    text = driver.getElementByAttribute(checkSnapshotElement).getText()
    if text != str('保存快照成功'):
        raise SeleniumError(f'快照功能测试失败，返回信息是{text}')
    else:
        logger.info(text)
        return True

def instructions(instructionElement, checkInstructionElement, originalMenuElement):
    '''
    功能： 点击打开操作说明界面后，最后返回了原操作界面
    :param instructionElement:
    :param checkInstructionElement:
    :param originalMenuElement:
    :return:
    '''
    # 测试操作说明
    element = driver.getElementByAttribute(instructionElement)
    element.click()
    logger.info('测试【操作说明】功能')
    logger.info('点击“操作说明”')
    time.sleep(3)
    text = driver.getElementByAttribute(checkInstructionElement).getText()
    if text != str('净资本系统操作手册'):
        raise SeleniumError(f'未成功打开净资本系统操作手册，实际返回信息是{text}')
    else:
        logger.info("操作说明展示成功")
    # 返回原菜单
    element = driver.getElementByAttribute(originalMenuElement)
    element.click()
    time.sleep(1)
    return True

def confirm():
    # 弹出框确定
    driver.getAlert()

def cancel():
    # 弹出框取消
    driver.getAlert(alertFlag='dismiss')

def reset(clickElement):
    '''
    功能：点击重置按钮而已。log打印清晰
    :param clickElement:
    :return:
    '''
    elementObj = driver.getElementByAttribute(clickElement)
    elementObj.click()
    logger.info('点击“重置”')

def view(viewDataElement, viewElement):
    '''
    功能：选择某条数据，点击查看按钮
    :param viewDataElement: 要查看的元素
    :param viewElement: 查看的按钮元素
    :return:
    '''
    logger.info('测试【查看】功能')
    # 点击数据
    element = driver.getElementByAttribute(viewDataElement)
    element.click()
    # 查看元素
    element = driver.getElementByAttribute(viewElement)
    element.click()
    logger.info('点击“查看”')

def assign(assignDataElement, assignElement):
    '''
    功能：选择某条数据，点击派发按钮
    :param assignDataElement: 待派发的数据元素
    :param assignElement: 派发按钮元素
    :return:
    '''
    logger.info('测试【派发】功能')
    # 点击数据
    element = driver.getElementByAttribute(assignDataElement)
    element.click()
    # 派发元素
    element = driver.getElementByAttribute(assignElement)
    element.click()
    logger.info('点击“派发”')

def submit(submitDataElement, submitElement):
    '''
    功能：选择某条数据，点击提交审批按钮
    :param submitDataElement: 待提交的数据元素
    :param submitElement: 提交审批的按钮元素
    :return:
    '''
    logger.info('测试【提交审批】功能')
    # 点击数据
    element = driver.getElementByAttribute(submitDataElement)
    element.click()
    # 提交审批元素
    element = driver.getElementByAttribute(submitElement)
    element.click()
    logger.info('点击“提交审批”')

def clickExpand(statusElement, clickElement, rowNmae='', flag='+'):
    element = driver.getElementByAttribute(statusElement)
    text = element.getText()
    if text == flag:
        element = driver.getElementByAttribute(clickElement)
        element.click()
        logger.info(f'点击展开{rowNmae}')
    else:
        logger.info(f'{rowNmae}已经是展开状态')


# ------------ 以下都是写入操作 --------------------------------
def getMenu(menuName, elementObj=None, delay=0.3, isRefresh='是'):
    '''
    功能：根据菜单名称，在菜单列表中找到对应菜单并打开
    :param menuName: 菜单名称 //用于输入搜索框定位菜单位置
    :param elementObj: 目标菜单对应的xpath定位元素。
           根据菜单名称的通用写法，'xpath://a[@title="替换为菜单名称"]'。// 此参数可省略，会自动拼接
    :return:
    '''
    if not elementObj:
        elementObj = f'xpath://a[@title="{menuName}"]'
    if isRefresh == '是':
        browerRefresh()
    click('xpath://*[@id="frame_navigation_searchPanel"]/div[2]/div/a[3]', '刷新菜单', 0.2)
    click('xpath://*[@id="frame_navigation_searchPanel"]/div[2]/div/a[2]', '展开菜单', 0.8)
    logger.info('测试开始：定位到【%s】菜单' % menuName)
    driver.getElementByAttribute(elementObj).click()
    time.sleep(delay)


def write(message, elementObj, msg='', time_delay=0):
    '''
    功能：input输入框中写入值
    :param message: 要写入的信息
    :param elementObj: 查找定位的xpath元素
    :param msg: 写入信息的名称/输入框
    :return:
    '''
    element = driver.getElementByAttribute(elementObj)
    element.clear()
    element.send_keys(message)
    time.sleep(time_delay)
    logger.info('输入[%s]：%s' % (msg, message))


def writeTwo(message, elementObj ,msg=''):
    '''
    使用条件:可输入空值的场景,输入空值不跳过
    功能：input输入框中写入值
    :param message: 要写入的信息
    :param elementObj: 查找定位的xpath元素
    :param msg: 写入信息的名称/输入框
    :return:
    '''
    element = driver.getElementByAttribute(elementObj)
    element.clear()
    element.send_keys(message)
    logger.info('输入[%s]：%s' % (msg, message))


def writeMethod(msg, elementObj, sleep=0):
    '''
    功能：输入框中填入msg信息，并点击回车确认
    :param msg: 输入的信息
    :param elementObj: 输入框的定位元素
    :return:
    '''
    element = driver.getElementByAttribute(elementObj)
    element.clear()
    element.send_keys(msg)
    element.send_keys(Keys.ENTER)
    logger.info('输入信息为：%s' % msg)
    time.sleep(sleep)

def writeOfJS(rowElement, attributeName, value):
    '''
    功能：通过selenium实现对html属性进行修改的操作，单个属性修改
    :param rowElement:
    :param attributeName:
    :param value:
    :return:
    '''
    if value == ' ' or not value:
        logger.warning(f'输入信息为空，跳过！')
        return False
    eleobj = rowElement.split(':')[1]
    element = driver.findElement(eleobj)
    logger.info(element)
    driver.modifyAttriMethod(element, attributeName, value)
    logger.info(f'修改元素{element}的{attributeName}的属性值为{value}')

def writeInTable(rowElement, value, index=0):
    '''
    功能：往表格中写值，双击、写入再提交执行的方式
    :param element: 表格行的定位元素
        注意：针对添加后出现的行数是不固定的，不要把元素写死了。这里应该填能定位到多行元素的xpath，结合index进行操作
    :param value:
    :param index: 表格中的行数，0表示取第一行，-1表示取倒数第一行
    :return:
    '''
    if value == ' ' or not value:
        logger.warning(f'输入信息为空，跳过！')
        return False
    query_flag = False if index == 0 else True
    element = driver.getElementByAttribute(rowElement, getAll=query_flag)
    if not isinstance(element, list):
        element = [element]
    # 向表格中写入值，需要连续进行操作在提交执行。双击，输入后提交执行
    driver.writeTableInfo(element[index], value)
    logger.info(f'写入值：{value}')


def writeToTextarea(msg, textElement):
    '''
    往多行文本框中输入值
    :param msg: 
    :param rowElement: 
    :return: 
    '''
    element = driver.getElementByAttribute(textElement)
    driver.writeTableInfo(element, msg)
    logger.info(f'写入值：{msg}')

def writeInTableTwo(rowElement, value, index=0):
    '''
    使用条件:可输入空值的场景,输入空值不跳过
    功能：往表格中写值，双击、写入再提交执行的方式
    :param element: 表格行的定位元素
        注意：针对添加后出现的行数是不固定的，不要把元素写死了。这里应该填能定位到多行元素的xpath，结合index进行操作
    :param value:
    :param index: 表格中的行数，0表示取第一行，-1表示取倒数第一行
    :return:
    '''
    query_flag = False if index == 0 else True
    element = driver.getElementByAttribute(rowElement, getAll=query_flag)
    if not isinstance(element, list):
        element = [element]
    # 向表格中写入值，需要连续进行操作在提交执行。双击，输入后提交执行
    driver.writeTableInfo(element[index], value)
    logger.info(f'写入值：{value}')

def writeTableInput(rowElement, value, index=0):
    '''
    功能：往表格中写值，双击、写入再提交执行的方式
    :param element: 表格行的定位元素
        注意：针对添加后出现的行数是不固定的，不要把元素写死了。这里应该填能定位到多行元素的xpath，结合index进行操作
    :param value:
    :param index: 表格中的行数，0表示取第一行，-1表示取倒数第一行
    :return:
    '''
    if value == ' ' or not value:
        logger.warning(f'输入信息为空，跳过！')
        return False
    query_flag = False if index == 0 else True
    element = driver.getElementByAttribute(rowElement, getAll=query_flag)
    if not isinstance(element, list):
        element = [element]
    # 向表格中写入值，需要连续进行操作在提交执行。双击，输入后提交执行
    element[index].send_keys(value)
    logger.info(f'写入值：{value}')


def searchbox(message, elementObj):
    '''
    Function: 实现在搜索框中输入值，回车进行查询
    :param message:
    :param elementObj:
    :return:
    '''
    element = driver.getElementByAttribute(elementObj)
    element.clear()
    element.send_keys(message)
    element.send_keys(Keys.ENTER)
    logger.info('查询信息为：%s' % message)

def clear(clearElement, msg=''):
    '''
    功能：清空输入框中的值
    :param clearElement:
    :param msg:
    :return:
    '''
    # 点击清除
    element = driver.getElementByAttribute(clearElement)
    element.clear()
    logger.info('清除"%s"' % msg)


def getDate(date, elementObj):
    '''
    功能：查找输入日期的元素框，并将日期填入。
    // 就是正常查找元素，填充内容的方法，此处区别只是为了log打印清晰一点而已
    :param beginDate: 将要填入的日期
    :param elementObj: 日期对应的查找元素
    :return:
    '''
    # 获取日期
    element = driver.getElementByAttribute(elementObj)
    element.clear()
    element.send_keys(str(date))
    logger.info('输入日期为:%s' %date)


def getBeginDate(beginDate, elementObj):
    '''
    功能：查找输入日期的元素框，并将日期填入。
    // 就是正常查找元素，填充内容的方法，此处区别只是为了log打印清晰一点而已
    :param beginDate: 将要填入的开始日期
    :param elementObj: 开始日期对应的查找元素
    :return:
    '''
    # 获取起始日期
    element = driver.getElementByAttribute(elementObj)
    element.clear()
    element.send_keys(str(beginDate))
    logger.info('输入起始日期:%s' %beginDate)


def getEndDate(endDate, elementObj):
    '''
    功能：查找输入日期的元素框，并将日期填入。
    // 就是正常查找元素，填充内容的方法，此处区别只是为了log打印清晰一点而已
    :param endDate:
    :param elementObj:
    :return:
    '''
    # 获取结束日期
    element = driver.getElementByAttribute(elementObj)
    element.clear()
    element.send_keys(str(endDate))
    logger.info('输入结束日期:%s' %endDate)


def getCompany(company, elementObj):
    '''
    功能：查找输入公司名称的元素框，并将公司名称填入。
    // 就是正常查找元素，填充内容的方法，此处区别只是为了log打印清晰一点而已
    :param company:
    :param elementObj:
    :return:
    '''
    # 获取公司
    element = driver.getElementByAttribute(elementObj)
    element.clear()
    element.send_keys(company)
    element.send_keys(Keys.ENTER)
    logger.info('输入公司为:%s' % company)

# ------------ 以下都是选择操作 --------------------------------
# match()           // 已删除，请用selectOfList()替换  2021-8-13
# matchMethod()     // 已删除，重复功能   2021-8-13
# selectMethod()    // 已删除，方法笨重，用其他的替代

# selectOfList(message, selectElement, listElement, isFirst=True)       下拉列表，根据文本值选择
# selectTrees(msg, clickElement, ExpandElement, controlElement, selectElement, index=0)     下拉树，复选框，部门选择
# selectTree(msg, clickElement, controlElement, selectElement, index=0)   下拉树，复选框，部门选择，少一个全部展开的点击元素

def selectOfList(message, selectElement, listElement, isFirst=True, reserveElement=None):
    ''' 
    Function: 点击下拉框，找出所有的列表元素，根据文本信息匹配，成功后点击
    :param message: 下拉框要选择的目标值
    :param selectElement: 下拉元素
    :param listElement: 列表元素
    :return:
    '''
    if isinstance(message, str):
        message = message.split(',')
    element = driver.getElementByAttribute(selectElement)
    element.click()
    if reserveElement:
        element = driver.getElementByAttribute(reserveElement)
        element.click()
    if message == ' ' or not message:
        logger.warning(f'选择数据为空，跳过！')
        return False
    elements = driver.getElementByAttribute(listElement, getAll=True)
    for ele in elements:
        text = ele.getText()
        if text in message:
            ele.click()
            logger.info('选中的内容为:%s' % text)
            if isFirst:
                break


def selectSearchOflist(msg, clickElement, searchElement, controlElement):
    '''
    功能：主要是用于下拉框选择，找到 msg 的元素后进行点击完成勾选。// 只支持单选
    :param msg: 选择报表的名称，对应html标签中text的值，找到这个值后会点击选中 msg = 'a,b,c', isFirst=False '//*[@id="dojox_form__CheckedMultiSelectItem_515"]/div[2]'
    :param clickElement: 下拉框下拉按钮元素
    :param controlElement: 下拉框弹出的控件元素
    :return:
    '''
    if not isinstance(msg, list):
        msg = msg.split(',')
    for unit in msg:
        element = driver.getElementByAttribute(clickElement)
        element.click()
        element1 = driver.getElementByAttribute(searchElement)
        element1.clear()
        element1.send_keys(unit)
        element1.send_keys(Keys.ENTER)
        sleep(1)
        element2 = driver.getElementByAttribute(controlElement)
        if isinstance(element2, list):
            for ele in element2:
                ele.click()
        else:
            element2.click()
        logger.info('选中的内容为:%s' % unit)
        element3 = driver.getElementByAttribute(clickElement)
        element3.click()


def selectTreeOfTwoList(data, checkElement, infoElement):
    '''
    精简的树形结构，复选框勾选。最主要的应用部门选择！对比html的元素，如下的示例应该可以直接用。//主要还是方便元素定位
    参考结构：
        <li id="athena_dijit_form_TreeMixinSelect_0_popup_ztreeNode_3" class="level2" tabindex="0" hidefocus="true" treenode="">
            <span id="athena_dijit_form_TreeMixinSelect_0_popup_ztreeNode_3_switch" title="" class="button level2 switch center_docu" treenode_switch=""></span>
            <span id="athena_dijit_form_TreeMixinSelect_0_popup_ztreeNode_3_check" class="button chk checkbox_false_full" treenode_check=""></span>
            <a id="athena_dijit_form_TreeMixinSelect_0_popup_ztreeNode_3_a" class="level2" treenode_a="" onclick="" target="_blank" style="color:#333;font-weight:normal;" title="财通-风险管理部">
                <span id="athena_dijit_form_TreeMixinSelect_0_popup_ztreeNode_3_ico" title="" treenode_ico="" class="button Dept_ico_docu" style="">
                </span><span id="athena_dijit_form_TreeMixinSelect_0_popup_ztreeNode_3_span">财通-风险管理部</span>
            </a>
        </li>
    :param data: eg: "财通-风险管理部,财通-审计部"
    :param checkElement: 只包含前缀就好，不要含数字部门；此外前缀不能唯一确定的，需要添加第2个属性协助唯一定位
                        eg: "//span[starts-with(@id, 'athena_dijit_form_TreeMixinSelect_0_popup_ztreeNode') and @treenode_check]"
    :param infoElement: eg: "//a[starts-with(@id, 'athena_dijit_form_TreeMixinSelect_0_popup_ztreeNode')]"
    :return:
    '''
    dataList = data.split(",")
    checkListEles = driver.getElementByAttribute(checkElement, getAll=True)
    infoListEles = driver.getElementByAttribute(infoElement, getAll=True)
    if checkListEles and infoListEles and len(checkListEles) == len(infoListEles):
        for i, unit in enumerate(infoListEles):
            text = unit.getText()
            if text in dataList:
                logger.info(f'找到部门："{text}" ，勾选')
                checkEle = checkListEles[i]
                checkEle.click()
    else:
        logger.warning(f'查找结果为空或数量不一致，请检查并验证xpath表达式正确性！')
    return True


def selectTreesForDepartment(msg, clickElement=None, ExpandElement=None,
                             checkElement=None, aElement=None, searchElement=None, okElement=None):
    '''
    下拉列表，从下拉树中勾选对应的目标。例如部门选择，主要也是用于部门选择。已有方法的二次封装，可灵活应用。
    :param msg:
    :param clickElement:  下拉三角按钮，不传就不执行
    :param ExpandElement: 展开树按钮，不传就不执行
    :param checkElement:  参考selectTreeOfTwoList
    :param aElement:      参考selectTreeOfTwoList
    :param searchElement: 输入框输入搜索元素，不传就不执行
    :param okElement:     确认/保存按钮，不传就不执行
    :return:
    '''
    data = msg.split(',')
    logger.info(f'将要勾选的值是：{data}')
    # 下拉框控件匹配方法
    if clickElement:
        click(clickElement, '下拉三角')
    else:
        logger.warn(f"clickElement param {clickElement} is None, skip!")
    if ExpandElement:
        click(ExpandElement, '全部展开')
    else:
        logger.warn(f"clickElement param {ExpandElement} is None, skip!")
    if searchElement:
        for unit in data:                   # 通过搜索，一个一个的勾选添加
            writeMethod(unit, searchElement, 0.2)
            selectTreeOfTwoList(unit, checkElement, aElement)
    else:
        logger.warn(f"clickElement param {ExpandElement} is None, skip!")
        if checkElement and aElement:
            selectTreeOfTwoList(data, checkElement, aElement)
        else:
            logger.warn(f"checkElement param {checkElement} or aElement param {aElement} is None, skip!")
    if okElement:
        click(okElement, '确定')
    else:
        logger.warn(f"clickElement param {ExpandElement} is None, skip!")
    return True


def selectTrees(msg, clickElement, ExpandElement, controlElement, selectElement, index=0, time_delay=0):
    '''
    功能：用于操作风险，点击下拉元素，勾选下拉树中的符合条件的复选框，可以多选。例如部门选择
    :param msg: web界面上控件对应的名称，例如部门名称
    :param clickElement: 下拉三角形定位元素
    :param ExpandElement: 点击全部展开元素 // *********
    :param controlElement: 下拉树根节点元素，一定要是根节点，影响元素查找的准确性
    :param selectElement: 下拉树节点的选择元素，仅含部分，不含最后的id
    :param index: 用于将下拉树节点选择元素完整，index表示根节点起始的id，下面的节点会依次递增
    :return:
    '''
    ex_text = msg.split(',')
    logger.info(f'勾选的值是：{ex_text}')
    # 下拉框控件匹配方法
    element = driver.getElementByAttribute(clickElement)
    element.click()
    element = driver.getElementByAttribute(ExpandElement)
    element.click()
    elementList = driver.getElementByAttribute(controlElement, getAll=True)
    sleep(1)
    textList = []
    for element in elementList:
        textList = element.getText().split('\n')
    numlist = [i+index for i in range(len(textList))]
    temp_dic = dict(zip(textList, numlist))
    logger.info(temp_dic)
    for ex_temp in ex_text:
        ele_str = selectElement.format(temp_dic[ex_temp])
        element2 = driver.getElementByAttribute(ele_str)
        element2.click()
    time.sleep(time_delay)


def selectTree(msg, clickElement, controlElement, selectElement, index=0, time_delay=0):
    ''' 20210729 yuanxs 去掉全部展开元素
    功能：用于操作风险，点击下拉元素，勾选下拉树中的符合条件的复选框，可以多选。例如部门选择
    :param msg: web界面上控件对应的名称，例如部门名称
    :param clickElement: 下拉三角形定位元素
    :param controlElement: 下拉树根节点元素，一定要是根节点，影响元素查找的准确性
    :param selectElement: 下拉树节点的选择元素，仅含部分，不含最后的id
    :param index: 用于将下拉树节点选择元素完整，index表示根节点起始的id，下面的节点会依次递增
    :return:
    '''
    ex_text = msg.split(',')
    logger.info(f'勾选的值是：{ex_text}')
    # 下拉框控件匹配方法
    element = driver.getElementByAttribute(clickElement)
    element.click()
    elementList = driver.getElementByAttribute(controlElement, getAll=True)
    sleep(1)
    textList = []
    for element in elementList:
        textList = element.getText().split('\n')
    numlist = [i+index for i in range(len(textList))]
    temp_dic = dict(zip(textList, numlist))
    logger.info(temp_dic)
    for ex_temp in ex_text:
        ele_str = selectElement.format(temp_dic[ex_temp])
        element2 = driver.getElementByAttribute(ele_str)
        element2.click()
    time.sleep(time_delay)


def selectMethod(msg, elementObj1, elementObj2):
    '''
    Function: 点击下拉元素直接选择目标值点击 // 此方法不推荐哈，建议用selectOfList()
    :param msg:
    :param elementObj1:
    :param elementObj2:
    :return:
    '''
    element = driver.getElementByAttribute(elementObj1)
    element.clear()
    element.send_keys(str(msg))
    element = driver.getElementByAttribute(elementObj2)
    element.click()
    logger.info('输入信息为：%s' % msg)


def selectSearch(msg, elementObj1):
    '''
    Function:
    :param msg:
    :param elementObj1:
    :return:
    '''
    if msg == ' ' or not msg:
        logger.warning(f'选择数据为空，跳过！')
        return False
    element = driver.getElementByAttribute(elementObj1)
    element.clear()
    element.send_keys(msg)
    element.send_keys(Keys.ENTER)
    logger.info('输入信息为：%s' % msg)

def selectTarget(clickElement, listElement, targetname):
    '''
    功能：点击下拉元素，根据标识符筛选出列表中的目标元素进行点击
    // 此类是通过 listElement 和 targetname 直接拼接出目标项的xpath定位元素后直接点击，而非从下拉列表中筛选
    :param clickElement:
    :param listElement:
    :param targetname:
    :return:
    '''
    if targetname == ' ' or not targetname:
        logger.warning(f'选择数据为空，跳过！')
        return False
    element = driver.getElementByAttribute(clickElement)
    element.click()
    sleep(0.2)
    targetElement = listElement.format(targetname)
    logger.info(f'点击选择目标元素：{targetname}')
    element2 = driver.getElementByAttribute(targetElement)
    element2.click()


def select(msg, selectElement, searchElement):
    '''
    功能：点击下拉元素，在搜索输入框中输入关键字从列表中筛选出目标值，回车确认后即可填入
    :param msg:
    :param selectElement:
    :param searchElement:
    :return:
    '''
    if msg == ' ' or not msg:
        logger.warning(f'选择数据为空，跳过！')
        return False
    # 下拉框选择内容
    element = driver.getElementByAttribute(selectElement)
    element.click()
    element = driver.getElementByAttribute(searchElement)
    element.send_keys(msg)
    element.send_keys(Keys.ENTER)
    logger.info('选择的信息为：%s' %msg)

def selectTargetRow(selectElement, content=None, tableElement=None):
    '''
    功能：下拉树，勾选目标值对应的复选框
    场景：查询界面，根据编号或名称，在对应的复选框打勾。如果编号或名称以及对应的元素为空时，默认勾选第1个
    :param selectElement: 复选框对应的元素，把区分行号的节点用{}占位符替代。
        // 'xpath://*[@id="frame_navigation_athena_dijit_TemplatePanel_25101050010-Grid"]/div[3]/div[4]/div[{}]/table/tbody/tr/td',
    :param content: 编号或名称
    :param tableElement: 编号或名称对应的表格元素，把区分行号的节点用*替代或把用于取数的 [2] 去掉。
        // 'xpath://*[@id="frame_navigation_athena_dijit_TemplatePanel_25101050010-Grid"]/div[3]/div[2]/div/table/tbody/tr/td[1]',
        // div[2]下存在多个 div/table/tbody/tr/td[1]，根据这个查询返回的是一个列表
    :return:
    '''
    index = 1
    if content and targetElement:
        elements = driver.getElementByAttribute(tableElement, True)
        for i, ele in enumerate(elements):
            if ele.getText() == content:
                index = i + 1
                break
    targetElement2 = selectElement.format(str(index))
    msg = f'第{index}个复选框'
    click(targetElement2, msg)

def selectOfRows(index, selectElement, listElement):
    '''
    Function: 点击添加/下拉后，根据index选择列表中的元素 // 应用场景少，尽量别选*******
    :param message:
    :param selectElement: 下拉/按钮元素
    :param listElement: 列表元素
    :param index: 针对表格，会有多行存在，可指定目标行数。例如点击添加时，有的在第1行，那么index=0默认即可，有的在最后一行，index需要设置为-1
    :return:
    '''
    if index == ' ' or not index:
        logger.warning(f'选择数据为空，跳过！')
        return False
    element = driver.getElementByAttribute(selectElement)
    logger.info(element)
    element.click()
    elements = driver.getElementByAttribute(listElement, getAll=True)
    logger.info(elements)
    elements[index].click()
    logger.info('选择的行数为：%s' % index)


def selectTable(targetValue, selectElement, listElement, clickElement=None):
    '''
    Function: 下拉选择表格中的元素进行点击，可以多选。一般用于日期的年和月的选择等
    :param targetValue: 
    :param selectElement: 
    :param listElement: 
    :return: 
    '''
    element = driver.getElementByAttribute(selectElement)
    logger.info(element)
    element.click()
    elements = driver.getElementByAttribute(listElement, getAll=True)
    listValue = [targetValue] if isinstance(targetValue, str) else targetValue
    for value in listValue:
        for element in elements:
            if element.getText() == value:
                element.click()
                logger.info(f'选中"{value}"点击')
    if clickElement:
        click(clickElement, '确定')
    return True

# ------------ 以下都是数据查找操作 --------------------------------
def foundList(checkElement):
    '''
    Funciton: 根据定位元素获取对应列所有元素的文本值
    :param checkElement:
    :return:
    '''
    reslist = []
    elemetns = driver.getElementByAttribute(checkElement, getAll=True)
    for element in elemetns:
        text = element.getText()
        if text:
            reslist.append(text)
    res_str = ','.join(reslist)
    res_list2 = list(set(reslist))
    logger.info(f'获取的数据列：{res_list2}')
    return res_list2

def foundTargetElement(element, flag=0, timeout=30):
    '''
    显示等待，等待元素加载或判断其他条件成立
    :param exceptElement: 期望出现的元素
    :param flag:
        0：判断指定元素是否加载出来
        1: 判断所有元素是否已经加载完成
        2：判断元素是否被选中
        3：判断frame是否可切入，可传入locator元组或者直接传入定位方式：id、name、index或WebElement
        4: 判断元素的 text 是否包含预期字符串
        5: 与0相反，判断某个元素消失继续
        other：判断一个元素是否仍在DOM中，传入WebElement对象，可以判断页面是否刷新了
    :param timeout: 超时时间，默认30s
    :return: 得到期望值返回True，如果超时都未找到则返回False
            '''
    res_found = driver.display_wait(element, flag=flag, timeout=timeout)
    logger.info(f'返回结果是:{res_found}')
    return res_found

def foundEleAttribute(targetElement, attriName):
    ele = driver.getElementByAttribute(targetElement)
    res = ele.getAttribute(attriName)
    logger.info(f'找到元素{attriName}的属性值是{res}')
    return res

def foundEleText(targetElement):
    ele = driver.getElementByAttribute(targetElement)
    res = ele.getText()
    logger.info(f'找到元素的文本值是{res}')
    return res


# ------------ 以下都是检查操作 --------------------------------
def isElementPresent(element, flag=True, timeout=10, fre_time=0.5):
    '''
    功能：检查元素是否存在
    :param element:
    :return:
    '''
    # 元素是否存在
    temp = element.split(':')
    elementObj = driver.findElement(temp[1], flag=flag, timeout=timeout, fre_time=fre_time)
    if elementObj:
        logger.info('页面元素已经找到!')
        return True
    else:
        logger.error('页面元素没有找到！！！')
        return False

def assertResult(result, expectMessage='', checkMessage=''):
    if result:
        msg = "成功!"
        logger.info('断言结果为：%s' % msg)
        return True
    else:
        msg = "失败!"
        driver.getScreen()
        logger.error('断言结果为：%s' % msg)
        raise SeleniumError("断言失败！期望信息为：{}，断言信息为：{}".format(expectMessage, checkMessage))

def assertTwoResult(expResult, resResult):
    expResult = expResult if isinstance(expResult, str) else str(expResult)
    resResult = resResult if isinstance(resResult, str) else str(resResult)
    logger.info(f'expResult:{expResult}, {type(expResult)}')
    logger.info(f'resResult:{resResult}, {type(resResult)}')
    if expResult == resResult:
        msg = "成功!"
        logger.info('断言结果为：%s' % msg)
        return True
    else:
        msg = "失败!"
        driver.getScreen()
        logger.error('断言结果为：%s' % msg)
        raise SeleniumError(F"断言失败！期望信息为：{expResult}，断言信息为：{resResult}")

def checkDataNum(foundElement, index=0):
    reslst =foundList(foundElement)
    logger.info(reslst)
    check_res = cmp_count(reslst,index)
    assertResult(check_res)


def checkEleStatus(expResult, tarElement, flag=0, timeout=10):
    '''
    查找元素出现或小型
    :param expResult:
    :param tarElement:
    :param flag:
        0：判断指定元素是否加载出来
        1: 判断所有元素是否已经加载完成
        5: 与0相反，判断某个元素消失继续
    :param timeout:
    :return:
    '''
    chect_res = foundTargetElement(tarElement, flag=flag, timeout=timeout)
    assertTwoResult(expResult, chect_res)


def checkAlterResult(expResult, expElement):
    res = isElementPresent(expElement)
    assertTwoResult(expResult, res)


def checkEleText(expResul, tarElement):
    res = foundEleText(tarElement)
    assertTwoResult(expResul, res)


def checkDate(min, max, rowElement, format='%Y-%m-%d', split_flag=None):
    expect_info = f'min：{min}，max:{max}'
    target_info = ''
    # if cmp_state(min, max):
    #     logger.warning(f'期望范围为空，跳过校验！')
    #     return False
    flag = True
    resList = foundList(rowElement)
    for unit in resList:
        if split_flag:
            unit = unit.split(split_flag)[0]
        res = cmp_date(unit, min, max, format)
        if res == False:
            flag = False
            target_info = unit
    assertResult(flag, expect_info, target_info)


def checkData(expectData, rowElement):
    '''
    校验某一列的元素，是否都跟根据查询条件查询出来的
    :param expectData: str|list 查询条件或检查元素
    :param rowElement: 查询后显示表格的列定位元素
    :return:
    '''
    expect_info = f'data:{expectData}'
    target_info = ''
    # if not expectData or expectData == ' ':
    #     logger.warning(f'校验数据为空，跳过校验！')
    #     return False
    flag = True
    resList = foundList(rowElement)
    for unit in resList:
        res = cmp_contain(unit, expectData)
        if not res:
            flag = False
            target_info = unit
    assertResult(flag, expect_info, target_info)


def checkAmount(min, max, rowElement):
    expect_info = f'min：{min}，max:{max}'
    target_info = ''
    flag = True
    # if cmp_state(min, max):
    #     logger.warning(f'校验数据为空，跳过校验！')
    #     return False
    resList = foundList(rowElement)
    for unit in resList:
        res = cmp_value(unit, min, max)
        if res == False:
            flag = False
            target_info = unit
    assertResult(flag, expect_info, target_info)


def checkFileExit(filename):
    '''
    检查下载后文件的名称是否和期望的一致
    '''
    downdir2 = os.path.join(ROOT_PATH, 'DownFiles')
    logger.info(downdir2)
    res_file = get_dir_file(downdir2)
    res_check = cmp_contain(res_file, filename)
    assertResult(res_check)


def check(expectMessage, checkElement, isStop=True, flag=1):
    '''
    功能：校验是否跳转到了指定页面。判断checkElement对应的text文本信息是否等于expectMessage
    :param expectMessage: str 类型，填写界面上要查找的文本信息。示例："首页"
    :param checkElement: str 类型，填写html上对应的查找元素。示例："xpath:////*[@id="content_tablist"]/div[4]/div/div"
    :param isStop: Boolean 类型，断言失败后是否立即中断。True，立即中断退出，Flase，只返回结果Flase，脚本执行执行
    :param flag: int 类型，用于判断找到元素后是取元素的text值还是属性值。1，取html的text值；其他取html标签的text属性值
    :return: 检查结果为pass返回True，
             isStop=False时，检查结果为fail返回False，
             isStop=True时，检查结果为fail返回False，给平台返回可识别的固定异常信息：
                raise SeleniumError("断言失败！期望信息为：{}，断言信息为：{}".format(expectMessage, checkMessage))
    '''
    # if expectMessage == ' ' or not expectMessage:
    #     logger.warning(f'校验数据为空，跳过校验！')
    #     return False
    checkElementObj = driver.getElementByAttribute(checkElement)
    if checkElementObj is not None:
        if flag == 1:
            checkMessage = checkElementObj.getText()
        else:
            checkMessage = checkElementObj.getAttributeText()
    else:
        checkMessage = "没找到元素对应的文本"
    logger.info('进行【断言】')
    logger.info('期望信息为：%s' % expectMessage)
    logger.info('断言信息为：%s' % checkMessage)
    if expectMessage == str(checkMessage):
        msg = "成功!"
        logger.info('断言结果为：%s' % msg)
        return True
    else:
        msg = "失败!"
        driver.getScreen()
        logger.error('断言结果为：%s' % msg)
        if isStop:
            raise SeleniumError("断言失败！期望信息为：{}，断言信息为：{}".format(expectMessage, checkMessage))
        else:
            return False

# ------------ 以下都是上传导入操作 --------------------------------
def reportCheck(checkClickElement, uploadElement, uploadFile, cofirmElement):
    '''
    功能：上传文件并确认
    :param checkClickElement:
    :param uploadElement: //注意，这里是直接使用了findElement函数，所以输入参数直接填写 xpath 语句即可，也支持xpath不支持其他。不伦不类！
    :param uploadFile:
    :param cofirmElement:
    :return:
    '''
    elementObj = driver.getElementByAttribute(checkClickElement)
    elementObj.click()
    logger.info('测试【报表校验】功能')
    logger.info('点击“校验”')
    elementObj= driver.findElement(uploadElement)
    elementObj.send_keys(uploadFile)
    time.sleep(1)
    logger.info('导入“校验报表”')
    elementObj = driver.getElementByAttribute(cofirmElement)
    elementObj.click()
    logger.info('点击“确定”')
    time.sleep(3)


def uploadAnnexFile(filename, linkElement, fileElement, checkElement, saveElement):
    '''
    封装的上传附件步骤；[除第1个上传链接元素linkElement，每个页面不唯一，需重新定位；其他后3个元素，因共用组件，元素应该是不变的无需再次定位，可直接用] 
    :param filename: 附件的全路径
    :param linkElement: 上传附件的超链接元素 【示例1：xpath://*[@id="athena_dijit_TemplatePanel_0-problem_pane"]/table/tbody/tr/td[2]/div[3]/a】
    :param fileElement: 上传附件时选择文件按钮元素 xpath://*[@id="athena_dijit_TemplatePanel_5-previewForm"]/span
    :param checkElement: 上传附件后的列表检查元素 xpath://*[@id="athena_dijit_TemplatePanel_5-reportList"]/table/tbody/tr
    :param saveElement: 上传附件按钮元素 xpath://*[@id="athena_dijit_TemplatePanel_5-uploadDiv"]/div/span
    :return:
    '''
    click(linkElement, '上传')
    uploadFile(fileElement, filename)
    checkEleStatus(True, checkElement, timeout=5)
    click(saveElement, '文件上传')
    return True

def uploadFile(clickElement, filepath):
    '''
    功能：上传附件，通过win32操作实现。区别于form表单上传
    :param clickElement: html对应的选择文件按钮元素
    :param filepath: 文件全路径
    :return:
    '''
    element = driver.getElementByAttribute(clickElement)
    element.click()
    sleep(2)
    uploadWin32(filepath)
    logger.info(f'上传附件：{filepath}')

def upload(clickElement, uploadElement, uploadFile, cofirmElement):
    '''
    功能：用于文件上传功能。
    :param clickElement: 上传按钮元素
    :param uploadElement: 文件路径输入元素
    :param uploadFile: 文件的全路径
    :param cofirmElement: 上传按钮元素
    :return:
    '''
    elementObj = driver.getElementByAttribute(clickElement)
    elementObj.click()
    logger.info('测试【导入】功能')
    logger.info('点击“导入”')
    elementObj= driver.findElement(uploadElement)
    elementObj.send_keys(uploadFile)
    time.sleep(1)
    logger.info('导入“附件”')
    elementObj = driver.getElementByAttribute(cofirmElement)
    elementObj.click()
    logger.info('点击“确定”')
    time.sleep(2)

# ------------ 以下都是JS操作 --------------------------------
def act_js_script(js_script, msg):
    '''
    功能：执行js脚本
    :param js_script: js脚本语句
    :param msg: 打印信息而已
    :return:
    '''
    # 执行js脚本
    logger.info(f'执行的JS脚本：{js_script}')
    driver.action_js(js_script=js_script)
    logger.info('点击"%s"' %msg)
    sleep(0.5)

def operateAttributes(rowElement, attributeList):
    '''
    功能：通过selenium实现对html属性进行增删改查的操作
    :param rowElement: 定位元素的xpath表达式
    :param attributeList: 对属性进行操作的列表，列表中是元组，元组的第1个代表操作方式，第2个代表属性名称，第3个代表属性值
        eg: [
              ('remove', 'readonly'),           // 移除属性
              ('get', 'title'),                 // 获取属性
              ('set', 'title', '2018'),         // 添加或修改属性
              ('modify', 'title', '2018')       // 修改属性
          ]
    :return:
    '''
    eleobj = rowElement.split(':')[1]
    element = driver.findElement(eleobj)
    logger.info(element)
    for attr in attributeList:
        if attr[0] == 'get':
            res = driver.getAttriMethod(element, attr[1])
            logger.info(f'获取元素{element}的{attr[1]}的属性值为{res}')
        elif attr[0] == 'remove':
            driver.removeAttriMethod(element, attr[1])
            logger.info(f'移除元素{element}的{attr[1]}的属性')
        elif attr[0] == 'set':
            driver.setAttriMethod(element, attr[1], attr[2])
            logger.info(f'添加元素{element}的{attr[1]}的属性值为{attr[2]}')
        elif attr[0] == 'modify':
            driver.modifyAttriMethod(element, attr[1], attr[2])
            logger.info(f'修改元素{element}的{attr[1]}的属性值为{attr[2]}')
        else:
            logger.warning(f'对属性的操作错误，只支持get，remove，set, modify等操作')
    return True

# ------------ 以下都是特殊功能函数 --------------------------------
def getHandleText(textElement):
    '''
    功能：获取元素的text值
    :param textElement:
    :return:
    '''
    elementObj = driver.getElementByAttribute(textElement)
    time.sleep(1)
    text = elementObj.getText()
    logger.info('操作列表信息:%s'% text)
    return text

def getCurrentDate(flag = None):
    '''
    功能：获取当前日期，格式化输出日期字符串：年-月-日
    :param flag: int 类型，被减的天数
    :return:
    '''
    year = str(int(datetime.datetime.now().strftime('%Y')))
    month = str(int(datetime.datetime.now().strftime('%m')))
    if flag == None:
        day = str(int(datetime.datetime.now().strftime('%d')))
        currentDate = year + '-' + month + '-' + day
    else:
        day = str(int(datetime.datetime.now().strftime('%d')) - flag)
        currentDate = year + '-' + month + '-' + day
    return currentDate

def countColInfoOfTable(colElement, flag=True):
    '''
    Function: 统计某一列中所有的文本值，并判断是否做去重处理
    :param colElement: 目标列的元素
    :param flag: 是否去除重复的元素
    :return:
    '''
    infList = []
    elementList = driver.getElementByAttribute(colElement, getAll=True)
    if len(elementList) > 0:
        for element in elementList:
            text = element.getText()
            infList.append(text)
    if infList:
        infList = list(set(infList))
    return infList

def getElementInfo(colElement):
    '''
    Function: 统计行数
    :param colElement:
    :return:
    '''
    num = 0
    elementList = driver.getElementByAttribute(colElement, getAll=True)
    return len(elementList)

# ------------ 以下都是净资本具体场景封装 --------------------------------
def auditControl(msgName, msgFlag):
    '''
    功能：净资本审核步骤封装
    :param msgName:
    :param msgFlag:
    :return:
    '''
    # 打开审核开关菜单
    getMenu('审核项信息手工设置', 'xpath://a[@title="审核项信息手工设置"]')
    # 输入审核名称
    writeMethod(msgName, 'xpath://*[@id="frame_navigation_athena_dijit_TemplatePanel_2100044-1"]/div[2]/form/div/div[2]/div/input')
    # 点击查询
    query('xpath://*[@id="frame_navigation_athena_dijit_TemplatePanel_2100044-1"]/div[1]/button[1]')
    # 修改启用标志数据
    update('xpath://*[@id="frame_navigation_athena_dijit_TemplatePanel_2100044_sollid"]/div[2]/div[1]/div/table/tbody/tr[1]/td[1]', 'xpath://*[@id="frame_navigation_athena_dijit_TemplatePanel_2100044-btn_Modify"]/span')
    # 修改启用标志
    select(msgFlag, 'xpath://*[@id="frame_navigation_athena_dijit_TemplatePanel_2100044_sollid"]/div[2]/div[1]/div/table/tbody/tr[1]/td[4]/div/div', 'xpath://*[@id="select2-drop"]/div/input')
    # 保存
    save('xpath://*[@id="frame_navigation_athena_dijit_TemplatePanel_2100044-1"]/div[3]/div[6]/div[1]/div/div[2]/div[2]/button[3]/span')
    # 关闭审核菜单
    # click('xpath://*[@id="content_tablist"]/div[4]/div/div[2]/span[3]', '关闭【审核项信息手工设置】')

def audit(auditUsername, msgPwd, menuName, msgFlag):
    '''
    功能：净资本切换用户，审核步骤封装
    :param auditUsername:
    :param msgPwd:
    :param menuName:
    :param msgFlag:
    :return:
    '''
    # 切换审核用户
    click('xpath://*[@id="frame_user"]', '用户')
    click('xpath://*[@id="frame_btn_exit"]', '退出')
    driver.close()
    # 审核用户登入
    login(auditUsername, msgPwd)
    # 打开待审核信息处理
    getMenu('待审核信息处理', 'xpath://a[@title="待审核信息处理"]')
    # 输入审核项名称
    writeMethod(menuName, 'xpath://*[@id="frame_navigation_athena_dijit_TemplatePanel_2100045-autoId_13"]')
    # 点击查询
    query('xpath://*[@id="frame_navigation_athena_dijit_TemplatePanel_2100045-autoId_1_label"]')
    time.sleep(2)
    if msgFlag == '审核通过':
        # 选择审核数据
        click('xpath://*[@id="frame_navigation_athena_dijit_TemplatePanel_2100045-myGrid"]/div[2]/div/div[2]/table/tbody/tr/td/span', '待审核数据')
        # 审核通过
        click('xpath://*[@id="frame_navigation_athena_dijit_TemplatePanel_2100045-auditPassBtn_label"]', '审核通过')
    else:
        # 选择审核数据
        click('xpath://*[@id="frame_navigation_athena_dijit_TemplatePanel_2100045-myGrid"]/div[2]/div/div[2]/table/tbody/tr/td/span', '待审核数据')
        # 审核不通过
        click('xpath://*[@id="frame_navigation_athena_dijit_TemplatePanel_2100045-auditNoPassBtn_label"]', '审核不通过')

def addRow(datas, input_elements):
    '''
    备注：此类应输入数据input_elements比较特殊，此处仅仅作为示例，建议具体应用时将此方法拷贝到目标脚本中，然后根据具体场景进行简单改动后应用。
    Function: 净资本，证券分类手工设置添加一行信息的封装。方便以数据驱动的方式进行调用，减少脚本重复步骤的书写，简化元素的查找。
    :param datas:  依据场景的特定的数据结构：{'证券代码': {'type': 'list', 'search_info': '600104'}}
                // 证券代码 表示列表的表名，也用于拼接定位元素的属性值
                // type: 有list,date,input三中类型，也对应3个输入方式或定位元素
                // search_info： 搜索框、输入框填写的信息值
    :param input_elements: 行定位元素字典集合，value="{}”中{}中的值会被 列表名 进行填充
             {  '下拉框元素': 'xpath://td[@value="{}"]/div/div/div/a',
                '搜索框元素': 'xpath://*[@id="select2-drop"]/div/input',
                '日期输入元素': 'xpath://td[@value="{}"]/div/div/div/div[3]/input[1]',
                '备注输入元素': 'xpath://td[@value="{}"]/div/div/input'}
    :return:
    '''
    for col_name, dic in datas.items():
        type_op, key_info = dic['type'], dic['search_info']
        logger.info(col_name + ":" + type_op + ":" + key_info)
        if type_op == 'list':
            ele1 = input_elements.get('下拉框元素').format(col_name)
            ele2 = input_elements.get('搜索框元素')
            select(key_info, ele1, ele2)
        elif type_op == 'date':
            ele3 = input_elements.get('日期输入元素').format(col_name)
            write(key_info, ele3, col_name)
        elif type_op == 'input':
            ele4 = input_elements.get('备注输入元素').format(col_name)
            write(key_info, ele4, col_name)
        else:
            logger.warning('不知道的类型，请检查！')
    return True

if __name__ == "__main__":
    pass













